package com.kwdb.importtool.core;

import com.kwdb.importtool.model.SQLStatement;
import com.kwdb.importtool.util.FileUtils;
import com.kwdb.importtool.util.LoggerUtil;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * SQL文件解析器
 * 负责解析MySQL导出的SQL文件，将其拆分为独立的SQL语句
 */
@Data
public class SQLParser {
    private static final Logger logger = LoggerFactory.getLogger(SQLParser.class);

    // 配置选项
    private boolean removeComments = true;
    private boolean removeEmptyLines = true;
    private boolean normalizeWhitespace = true;
    private int maxStatementLength = 10 * 1024 * 1024;
    private int maxChunkSize = 2 * 1024 * 1024;
    private boolean fixJsonEscaping = true; // 新增：修复JSON转义问题

    // 正则表达式模式
    private Pattern commentPattern;
    private Pattern delimiterPattern;
    private Pattern createTablePattern;
    private Pattern insertPattern;
    private Pattern singleQuotePattern;
    private Pattern doubleQuotePattern;
    private Pattern jsonPattern;

    // 状态变量
    private String currentDelimiter = ";";
    private boolean inMultiLineComment = false;
    private boolean inSingleQuote = false;
    private boolean inDoubleQuote = false;
    private StringBuilder currentStatement;
    private int currentLineNumber = 0;

    public SQLParser() {
        initializePatterns();
    }

    /**
     * 初始化正则表达式模式
     */
    private void initializePatterns() {
        // 注释模式
        commentPattern = Pattern.compile(
                "(?:--[^\\r\\n]*)|(?:#.*)|(/\\*.*?\\*/)",
                Pattern.CASE_INSENSITIVE | Pattern.DOTALL
        );

        // 分隔符模式
        delimiterPattern = Pattern.compile(
                "^\\s*DELIMITER\\s+(.+)$",
                Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
        );

        // SQL语句模式
        createTablePattern = Pattern.compile(
                "CREATE\\s+TABLE\\s+(?:IF NOT EXISTS\\s+)?`?(\\w+)`?",
                Pattern.CASE_INSENSITIVE
        );

        insertPattern = Pattern.compile(
                "INSERT\\s+INTO\\s+`?(\\w+)`?",
                Pattern.CASE_INSENSITIVE
        );

        // 引号模式
        singleQuotePattern = Pattern.compile("'");
        doubleQuotePattern = Pattern.compile("\"");

        // JSON模式 - 识别JSON字段
        jsonPattern = Pattern.compile(
                "'\\s*\\{\\\\*\"(?:[^\"\\\\]|\\\\.)*\"\\\\*:\\s*(?:[^,'\\}]|\\\\.)*\\}'",
                Pattern.CASE_INSENSITIVE
        );
    }

    /**
     * 解析SQL文件
     */
    public List<SQLStatement> parseFile(String filePath) throws IOException {
        logger.info("Parsing SQL file: {}", filePath);

        File file = new File(filePath);
        if (!file.exists() || !file.isFile()) {
            throw new IOException("SQL file not found: " + filePath);
        }

        logger.debug("成功读取文件: {} (大小: {} 字节)", file.getPath(), file.length());

        List<SQLStatement> statements = new ArrayList<>();
        StringBuilder contentBuilder = new StringBuilder();

        int bufferSize = 65536;          // 64KB 缓冲区
        int chunkSize = 2097152;         // 2MB 每个分块大小
        int overlapSize = 4096;          // 4KB 重叠区域

        try (FileInputStream fis = new FileInputStream(file);
             InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
             BufferedReader reader = new BufferedReader(isr, bufferSize)) {

            char[] buffer = new char[bufferSize];
            int charsRead;
            long totalCharsProcessed = 0;
            int chunkCount = 0;

            while ((charsRead = reader.read(buffer)) != -1) {
                contentBuilder.append(buffer, 0, charsRead);
                totalCharsProcessed += charsRead;

                if (contentBuilder.length() >= chunkSize) {
                    chunkCount++;
                    logger.debug("Processing chunk {} (total chars processed: {})", chunkCount, totalCharsProcessed);

                    // 找到最后一个分号位置，确保SQL语句完整性
                    String partialContent = contentBuilder.toString();
                    int lastSemicolon = partialContent.lastIndexOf(';');

                    if (lastSemicolon != -1) {
                        // 分割到最后一个分号
                        String completeChunk = partialContent.substring(0, lastSemicolon + 1);
                        String remaining = partialContent.substring(lastSemicolon + 1);

                        List<SQLStatement> partialStatements = parseContentSafely(completeChunk, filePath + " (chunk " + chunkCount + ")");
                        if (partialStatements != null) {
                            statements.addAll(partialStatements);
                        }

                        contentBuilder.setLength(0);
                        contentBuilder.append(remaining);
                    } else {
                        // 如果没有找到分号，按原逻辑处理但保留更多内容
                        List<SQLStatement> partialStatements = parseContentSafely(partialContent, filePath + " (chunk " + chunkCount + ")");
                        if (partialStatements != null) {
                            statements.addAll(partialStatements);
                        }

                        int keepLength = Math.min(overlapSize, contentBuilder.length());
                        String remaining = contentBuilder.substring(contentBuilder.length() - keepLength);
                        contentBuilder.setLength(0);
                        contentBuilder.append(remaining);
                    }

                    if (chunkCount % 10 == 0) {
                        System.gc();
                        logger.debug("GC called after {} chunks", chunkCount);
                    }
                }
            }

            if (contentBuilder.length() > 0) {
                String remainingContent = contentBuilder.toString();
                List<SQLStatement> remainingStatements = parseContentSafely(remainingContent, filePath + " (final chunk)");
                if (remainingStatements != null) {
                    statements.addAll(remainingStatements);
                }
            }
        } catch (OutOfMemoryError e) {
            logger.error("内存不足错误 while parsing file: {}", filePath, e);
            System.gc();
            throw new IOException("文件太大，解析过程中内存不足: " + filePath, e);
        } catch (Exception e) {
            logger.error("解析文件时发生错误: {}", filePath, e);
            throw new IOException("解析文件失败: " + filePath, e);
        }

        logger.info("成功解析 {} 条SQL语句 from {}", statements.size(), filePath);
        return statements;
    }

    /**
     * 安全的解析内容方法
     */
    private List<SQLStatement> parseContentSafely(String content, String source) {
        try {
            return parseContent(content, source);
        } catch (OutOfMemoryError e) {
            logger.error("内存不足 while parsing content chunk: {}", source, e);
            System.gc();
            return null;
        } catch (Exception e) {
            logger.warn("解析内容块时发生错误 (source: {}), 错误: {}", source, e.getMessage());
            return new ArrayList<>();
        }
    }

    /**
     * 解析SQL内容 - 修复JSON转义问题
     */
    public List<SQLStatement> parseContent(String content, String source) {
        if (content.length() > 10 * 1024 * 1024) {
            logger.warn("内容块过大 ({} 字符)，进行强制分割", content.length());
            return splitAndParseLargeContent(content, source);
        }

        List<SQLStatement> statements = new ArrayList<>();

        try {
            content = removeCommentsWithNewlines(content);

            // 修复JSON转义问题
            if (fixJsonEscaping) {
                content = fixJsonEscapeCharacters(content);
            }

            List<String> statementTexts = splitBySemicolon(content);

            for (int i = 0; i < statementTexts.size(); i++) {
                String sql = statementTexts.get(i);
                String trimmedSql = fastTrim(sql);
                if (trimmedSql.isEmpty()) {
                    continue;
                }

                // 处理超长INSERT语句
                if (trimmedSql.indexOf("ed53ab9e-f9ab-4869-ac3b-64ac680547f4") != -1 || trimmedSql.indexOf("(7003,") != -1) {
                    logger.info("result:===="+ trimmedSql);
                }
                if (trimmedSql.toUpperCase().startsWith("INSERT INTO") && trimmedSql.length() > 500000) {
                    logger.info("发现超长INSERT语句 ({} 字符)，进行分批处理", trimmedSql.length());
                    List<String> splitInserts = splitLargeInsertStatement(trimmedSql);
                    for (String splitSql : splitInserts) {
                        if (!isCommentOrEmpty(splitSql)) {
                            SQLStatement statement = createSQLStatement(splitSql, i + 1);
                            statements.add(statement);
                        }
                    }
                } else if (!isCommentOrEmpty(trimmedSql) &&
                        !trimmedSql.toUpperCase().startsWith("LOCK") &&
                        !trimmedSql.toUpperCase().startsWith("UNLOCK TABLES") &&
                        !trimmedSql.toUpperCase().startsWith("DELIMITER") &&
                        !trimmedSql.toUpperCase().startsWith("SET")
                ) {
                    SQLStatement statement = createSQLStatement(trimmedSql, i + 1);
                    statements.add(statement);

                    if (trimmedSql.length() > maxStatementLength) {
                        logger.warn("发现超长SQL语句 ({} 字符)，但会继续处理", trimmedSql.length());
                    }
                }

                if (statements.size() % 1000 == 0) {
                    logger.debug("已解析 {} 条语句 from {}", statements.size(), source);
                    if (statements.size() % 5000 == 0) {
                        System.gc();
                    }
                }
            }

            logger.info("Parsed {} SQL statements from {}", statements.size(), source);
        } catch (OutOfMemoryError e) {
            logger.error("内存不足 while parsing content: {}", source, e);
            System.gc();
            throw e;
        } catch (Exception e) {
            logger.error("解析SQL内容时发生错误 (source: {})", source, e);
            throw e;
        }

        return statements;
    }

    /**
     * 修复JSON转义字符问题
     */
    private String fixJsonEscapeCharacters(String content) {
        if (content == null || content.isEmpty()) {
            return content;
        }

        StringBuilder result = new StringBuilder(content.length());
        boolean inJson = false;
        boolean inSingleQuote = false;
        boolean inDoubleQuote = false;
        int jsonDepth = 0;
        char prevChar = '\0';

        for (int i = 0; i < content.length(); i++) {
            char c = content.charAt(i);

            // 处理转义字符
            if (prevChar == '\\') {
                // 如果在JSON内部，需要处理转义
                if (inJson && inDoubleQuote) {
                    // 对于JSON内部的转义，确保正确的转义序列
                    if (c == '\\' || c == '"' || c == '/' || c == 'b' || c == 'f' || c == 'n' || c == 'r' || c == 't') {
                        result.append('\\').append(c);
                    } else if (c == 'u') {
                        // Unicode转义序列
                        if (i + 4 < content.length()) {
                            result.append('\\').append(c);
                        } else {
                            result.append(c);
                        }
                    } else {
                        // 无效的转义序列，移除转义字符
                        result.append(c);
                    }
                } else {
                    // 非JSON区域的转义，保持原样
                    result.append('\\').append(c);
                }
                prevChar = c;
                continue;
            }

            // 处理引号状态
            if (c == '\'' && !inDoubleQuote) {
                inSingleQuote = !inSingleQuote;
                result.append(c);
            } else if (c == '"' && !inSingleQuote) {
                inDoubleQuote = !inDoubleQuote;
                result.append(c);

                // 检测JSON开始
                if (!inJson && inDoubleQuote && i > 0 && content.charAt(i-1) == '\'') {
                    // 可能是JSON字段的开始：'{"...'
                    inJson = true;
                    jsonDepth = 1;
                }
            } else if (c == '{' && inDoubleQuote && inJson) {
                jsonDepth++;
                result.append(c);
            } else if (c == '}' && inDoubleQuote && inJson) {
                jsonDepth--;
                result.append(c);
                if (jsonDepth == 0) {
                    inJson = false;
                }
            } else {
                result.append(c);
            }

            prevChar = c;
        }

        return result.toString();
    }

    /**
     * 简化的JSON修复方法 - 使用正则表达式
     */
    private String fixJsonEscapingSimple(String content) {
        // 匹配JSON格式的字段：'{"key": "value"}'
        Pattern jsonPattern = Pattern.compile("'\\s*\\{(.*?)}\\s*'", Pattern.DOTALL);
        Matcher matcher = jsonPattern.matcher(content);

        StringBuffer result = new StringBuffer();
        while (matcher.find()) {
            String jsonContent = matcher.group(1);
            // 修复常见的JSON转义问题
            String fixedJson = jsonContent
                    .replace("\\\\", "\\")  // 减少多余的转义
                    .replace("\\'", "'")    // 单引号转义
                    .replace("\\\"", "\""); // 双引号转义

            matcher.appendReplacement(result, "'{" + fixedJson + "}'");
        }
        matcher.appendTail(result);

        return result.toString();
    }

    /**
     * 创建SQLStatement对象
     */
    private SQLStatement createSQLStatement(String sql, int lineNumber) {
        SQLStatement statement = new SQLStatement();
        statement.setOriginalSQL(sql);
        statement.setLineNumber(lineNumber);
        statement.setStatementType(determineStatementType(sql));
        statement.setTableName(extractTableName(sql));
        return statement;
    }

    /**
     * 分割超长INSERT语句
     */
    private List<String> splitLargeInsertStatement(String insertSql) {
        List<String> result = new ArrayList<>();

        try {
            String upperSql = insertSql.toUpperCase();
            int valuesIndex = upperSql.indexOf("VALUES");
            if (valuesIndex == -1) {
                result.add(insertSql);
                return result;
            }

            String insertPrefix = insertSql.substring(0, valuesIndex + 6).trim();
            String valuesContent = insertSql.substring(valuesIndex + 6).trim();

            if (valuesContent.startsWith("(") && valuesContent.endsWith(")")) {
                valuesContent = valuesContent.substring(1, valuesContent.length() - 1).trim();
            }

            List<String> valueRecords = splitValueRecords(valuesContent);

            if (valueRecords.isEmpty() || valueRecords.size() <= 100) {
                result.add(insertSql);
                return result;
            }

            logger.info("将包含 {} 条记录的INSERT语句分割为多个批次", valueRecords.size());

            int batchSize = 100;
            for (int i = 0; i < valueRecords.size(); i += batchSize) {
                int end = Math.min(i + batchSize, valueRecords.size());
                List<String> batchRecords = valueRecords.subList(i, end);

                StringBuilder batchSql = new StringBuilder();
                batchSql.append(insertPrefix).append(" ");

                for (int j = 0; j < batchRecords.size(); j++) {
                    if (j == 0) {
                        batchSql.append("(").append(batchRecords.get(j)).append(")");
                    } else {
                        batchSql.append(",(").append(batchRecords.get(j)).append(")");
                    }
                }
                batchSql.append(";");

                result.add(batchSql.toString());
            }

            logger.info("已将INSERT语句分割为 {} 个批次", result.size());

        } catch (Exception e) {
            logger.error("分割INSERT语句失败，返回原语句: {}", e.getMessage());
            result.add(insertSql);
        }

        return result;
    }

    /**
     * 分割VALUES记录
     */
    private List<String> splitValueRecords(String valuesContent) {
        List<String> records = new ArrayList<>();
        if (valuesContent == null || valuesContent.isEmpty()) {
            return records;
        }

        StringBuilder currentRecord = new StringBuilder();
        int parenDepth = 0;
        boolean inSingleQuote = false;
        boolean inDoubleQuote = false;
        char prevChar = '\0';

        for (int i = 0; i < valuesContent.length(); i++) {
            char c = valuesContent.charAt(i);

            if (prevChar == '\\') {
                currentRecord.append(c);
                prevChar = c;
                continue;
            }

            if (c == '\'' && !inDoubleQuote) {
                inSingleQuote = !inSingleQuote;
            } else if (c == '"' && !inSingleQuote) {
                inDoubleQuote = !inDoubleQuote;
            }

            if (!inSingleQuote && !inDoubleQuote) {
                if (c == '(') {
                    if (parenDepth == 0) {
                        if (currentRecord.length() > 0) {
                            String record = currentRecord.toString().trim();
                            if (!record.isEmpty()) {
                                records.add(record);
                            }
                            currentRecord.setLength(0);
                        }
                    }
                    parenDepth++;
                } else if (c == ')') {
                    parenDepth--;
                    if (parenDepth == 0) {
                        continue;
                    }
                }
            }

            if (parenDepth > 0) {
                currentRecord.append(c);
            }

            prevChar = c;
        }

        if (currentRecord.length() > 0) {
            String lastRecord = currentRecord.toString().trim();
            if (!lastRecord.isEmpty()) {
                records.add(lastRecord);
            }
        }

        return records;
    }

    private List<SQLStatement> splitAndParseLargeContent(String content, String source) {
        List<SQLStatement> statements = new ArrayList<>();
        int chunkSize = 2 * 1024 * 1024;
        int overlap = 1000;

        for (int i = 0; i < content.length(); i += chunkSize) {
            int end = Math.min(i + chunkSize + overlap, content.length());
            String chunk = content.substring(i, end);

            try {
                List<SQLStatement> chunkStatements = parseContent(chunk, source + " [subchunk " + (i/chunkSize) + "]");
                if (chunkStatements != null) {
                    statements.addAll(chunkStatements);
                }
            } catch (Exception e) {
                logger.warn("解析子块时失败: {}", e.getMessage());
            }

            if (end >= content.length()) {
                break;
            }
        }

        return statements;
    }

    public List<String> splitBySemicolon(String content) {
        List<String> statements = new ArrayList<>();
        if (content == null || content.isEmpty()) {
            return statements;
        }

        if (content.length() > 5 * 1024 * 1024) {
            logger.warn("处理大内容块 ({} 字符)，使用保守模式", content.length());
            return splitBySemicolonConservative(content);
        }

        StringBuilder currentStatement = new StringBuilder(1024);
        boolean inSingleQuotes = false;
        boolean inDoubleQuotes = false;
        boolean inBackticks = false;
        boolean inBlockComment = false;
        char prevChar = '\0';
        int statementCount = 0;

        for (int i = 0; i < content.length(); i++) {
            char c = content.charAt(i);

            if (statementCount % 100 == 0 && Runtime.getRuntime().freeMemory() < 50 * 1024 * 1024) {
                logger.warn("内存紧张，但继续处理语句");
            }

            if (prevChar == '\\') {
                currentStatement.append(c);
                prevChar = c;
                continue;
            }

            if (inBlockComment) {
                if (c == '*' && i + 1 < content.length() && content.charAt(i + 1) == '/') {
                    inBlockComment = false;
                    i++;
                }
                prevChar = c;
                continue;
            }

            if (!inSingleQuotes && !inDoubleQuotes && !inBackticks &&
                    c == '/' && i + 1 < content.length() && content.charAt(i + 1) == '*') {
                inBlockComment = true;
                i++;
                prevChar = c;
                continue;
            }

            if (c == '\'' && !inDoubleQuotes && !inBackticks && !inBlockComment) {
                inSingleQuotes = !inSingleQuotes;
            } else if (c == '"' && !inSingleQuotes && !inBackticks && !inBlockComment) {
                inDoubleQuotes = !inDoubleQuotes;
            } else if (c == '`' && !inSingleQuotes && !inDoubleQuotes && !inBlockComment) {
                inBackticks = !inBackticks;
            }

            if (!inSingleQuotes && !inDoubleQuotes && !inBackticks && !inBlockComment) {
                if (c == '-' && i + 1 < content.length() && content.charAt(i + 1) == '-') {
                    while (i < content.length() && content.charAt(i) != '\n') {
                        i++;
                    }
                    if (i < content.length()) {
                        c = content.charAt(i);
                    } else {
                        break;
                    }
                } else if (c == '#') {
                    while (i < content.length() && content.charAt(i) != '\n') {
                        i++;
                    }
                    if (i < content.length()) {
                        c = content.charAt(i);
                    } else {
                        break;
                    }
                }
            }

            if (c == ';' && !inSingleQuotes && !inDoubleQuotes && !inBackticks && !inBlockComment) {
                if (currentStatement.length() > 0) {
                    String statement = fastTrim(currentStatement.toString());
                    if (!statement.isEmpty() && !isPureComment(statement)) {
                        statements.add(statement);
                        statementCount++;
                    }
                }
                currentStatement.setLength(0);
            } else if (!inBlockComment) {
                currentStatement.append(c);

                if (currentStatement.length() > maxStatementLength) {
                    logger.warn("发现超长SQL语句 ({} 字符)，但会继续处理", currentStatement.length());
                }
            }

            prevChar = c;
        }

        if (currentStatement.length() > 0) {
            String lastStatement = fastTrim(currentStatement.toString());
            if (!lastStatement.isEmpty() && !isPureComment(lastStatement)) {
                statements.add(lastStatement);
            }
        }

        return statements;
    }

    private List<String> splitBySemicolonConservative(String content) {
        List<String> statements = new ArrayList<>();
        if (content == null || content.isEmpty()) {
            return statements;
        }

        int start = 0;
        int semicolonPos;

        while ((semicolonPos = content.indexOf(';', start)) != -1) {
            String statement = content.substring(start, semicolonPos);
            String trimmed = fastTrim(statement);

            if (!trimmed.isEmpty() && !isPureComment(trimmed)) {
                statements.add(trimmed);
            }

            start = semicolonPos + 1;
        }

        if (start < content.length()) {
            String lastStatement = content.substring(start);
            String trimmed = fastTrim(lastStatement);
            if (!trimmed.isEmpty() && !isPureComment(trimmed)) {
                statements.add(trimmed);
            }
        }

        return statements;
    }

    public static String removeCommentsWithNewlines(String content) {
        if (content == null || content.isEmpty()) {
            return content;
        }

        if (content.length() > 1024 * 1024) {
            return removeCommentsSimple(content);
        }

        Pattern pattern = Pattern.compile("/\\*.*?\\*/", Pattern.DOTALL);
        return pattern.matcher(content).replaceAll("");
    }

    private static String removeCommentsSimple(String content) {
        StringBuilder result = new StringBuilder(content.length());
        boolean inBlockComment = false;

        for (int i = 0; i < content.length(); i++) {
            if (inBlockComment) {
                if (content.charAt(i) == '*' && i + 1 < content.length() && content.charAt(i + 1) == '/') {
                    inBlockComment = false;
                    i++;
                }
            } else {
                if (content.charAt(i) == '/' && i + 1 < content.length() && content.charAt(i + 1) == '*') {
                    inBlockComment = true;
                    i++;
                } else {
                    result.append(content.charAt(i));
                }
            }
        }

        return result.toString();
    }

    private boolean isPureComment(String statement) {
        if (statement == null || statement.isEmpty()) {
            return true;
        }

        String trimmed = fastTrim(statement);
        return trimmed.startsWith("--") ||
                trimmed.startsWith("#") ||
                (trimmed.startsWith("/*") && trimmed.endsWith("*/")) ||
                trimmed.startsWith("/*!");
    }

    private boolean isCommentOrEmpty(String statement) {
        if (statement == null || statement.isEmpty()) {
            return true;
        }

        String trimmed = fastTrim(statement);
        return trimmed.isEmpty() ||
                trimmed.startsWith("--") ||
                trimmed.startsWith("#") ||
                (trimmed.startsWith("/*") && trimmed.endsWith("*/")) ||
                trimmed.startsWith("/*!");
    }

    private SQLStatement.StatementType determineStatementType(String sql) {
        if (sql == null || sql.isEmpty()) {
            return SQLStatement.StatementType.OTHER;
        }

        String upperSQL = sql.toUpperCase();

        if (upperSQL.startsWith("CREATE DATABASE")) {
            return SQLStatement.StatementType.CREATE_DATABASE;
        } else if (upperSQL.startsWith("DROP DATABASE")) {
            return SQLStatement.StatementType.DROP_DATABASE;
        } else if (upperSQL.startsWith("CREATE TABLE")) {
            return SQLStatement.StatementType.CREATE_TABLE;
        } else if (upperSQL.startsWith("DROP TABLE")) {
            return SQLStatement.StatementType.DROP_TABLE;
        } else if (upperSQL.startsWith("ALTER TABLE")) {
            return SQLStatement.StatementType.ALTER_TABLE;
        } else if (upperSQL.startsWith("INSERT INTO")) {
            return SQLStatement.StatementType.INSERT;
        } else if (upperSQL.startsWith("CREATE INDEX")) {
            return SQLStatement.StatementType.CREATE_INDEX;
        } else if (upperSQL.startsWith("DROP INDEX")) {
            return SQLStatement.StatementType.DROP_INDEX;
        } else if (upperSQL.startsWith("CREATE SEQUENCE")) {
            return SQLStatement.StatementType.CREATE_SEQUENCE;
        } else if (upperSQL.startsWith("DROP SEQUENCE")) {
            return SQLStatement.StatementType.DROP_SEQUENCE;
        } else if (upperSQL.startsWith("COMMENT ON")) {
            return SQLStatement.StatementType.COMMENT;
        } else if (upperSQL.startsWith("USE ")) {
            return SQLStatement.StatementType.USE;
        } else if (upperSQL.startsWith("SET ")) {
            return SQLStatement.StatementType.SET;
        } else {
            return SQLStatement.StatementType.OTHER;
        }
    }

    private String extractTableName(String sql) {
        if (sql == null || sql.isEmpty()) {
            return null;
        }

        String upperSQL = sql.toUpperCase();

        try {
            if (upperSQL.startsWith("CREATE TABLE")) {
                Matcher matcher = createTablePattern.matcher(sql);
                if (matcher.find()) {
                    return matcher.group(1);
                }
            } else if (upperSQL.startsWith("INSERT INTO")) {
                Matcher matcher = insertPattern.matcher(sql);
                if (matcher.find()) {
                    return matcher.group(1);
                }
            } else if (upperSQL.startsWith("ALTER TABLE")) {
                String[] parts = sql.split("\\s+");
                if (parts.length >= 3) {
                    String tableName = parts[2];
                    return tableName.replace("`", "");
                }
            }
        } catch (Exception e) {
            logger.debug("Failed to extract table name from: {}", sql.substring(0, Math.min(100, sql.length())));
        }

        return null;
    }

    private String fastTrim(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }

        int len = str.length();
        int st = 0;
        char[] val = str.toCharArray();

        while ((st < len) && (val[st] <= ' ')) {
            st++;
        }
        while ((st < len) && (val[len - 1] <= ' ')) {
            len--;
        }

        return ((st > 0) || (len < str.length())) ? str.substring(st, len) : str;
    }

    @Data
    public static class FileStatistics {
        private int totalStatements;
        private long fileSize;
        private double averageStatementLength;
        private Map<SQLStatement.StatementType, Integer> statementTypeCounts;

        public FileStatistics() {
            statementTypeCounts = new HashMap<>();
        }

        public void printStatistics() {
            logger.info("=== SQL File Statistics ===");
            logger.info("Total statements: {}", totalStatements);
            logger.info("File size: {} bytes", fileSize);
            logger.info("Average statement length: {:.2f} characters", averageStatementLength);
            logger.info("Statement type breakdown:");
            for (Map.Entry<SQLStatement.StatementType, Integer> entry : statementTypeCounts.entrySet()) {
                logger.info("  {}: {}", entry.getKey(), entry.getValue());
            }
        }
    }

    public static class SQLParseException extends RuntimeException {
        private int lineNumber;

        public SQLParseException(String message, int lineNumber) {
            super(message + " at line " + lineNumber);
            this.lineNumber = lineNumber;
        }

        public SQLParseException(String message, int lineNumber, Throwable cause) {
            super(message + " at line " + lineNumber, cause);
            this.lineNumber = lineNumber;
        }

        public int getLineNumber() {
            return lineNumber;
        }
    }
}